<?php

/*
 * Copyright (C) 2009 - 2011 Pham Cong Dinh
 *
 * This file is part of Spica.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

/**
 * This class provides simple mechanism to encode and decode a string
 *
 * @category   spica
 * @package    core
 * @subpackage crypto
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      March 31, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Crypto.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class SpicaSimpleCrypt
{
    /**
     * Prevents object instantiation.
     */
    protected function __construct() {}

    /**
     * Encodes a string using a secret key.
     *
     * @param string $data  String to decode
     * @param string $key   Secret key
     * @param int    $shift Bitwise shift
     */
    public static function encode($data, $key, $shift = 9)
    {
        for ($r = $data, $i = 0, $length = strlen($r); $i < $length; $i++)
        {
            $r[$i] = chr(ord($data[$i]) ^ ($key >> $shift));
            $k     = (int)((ord($data[$i]) + $key) * 52845 + 22719);
        }

        return $r;
    }

    /**
     * Decodes a string using a secret key.
     *
     * @param string $data String to decode
     * @param string $key  Secret key
     * @param int    $shift Bitwise shift
     */
    public static function decode($data, $key, $shift = 9)
    {
        for ($i = 0, $length = strlen($data); $i < $length; $i++)
        {
            $data[$i] = chr(ord($data[$i]) ^ ($key >> $shift));
            $k        = (int)((ord($data[$i]) + $key) * 52845 + 22719);
        }

        return $data;
    }
}

/**
 * An implementation of Rail Fence cipher.
 *
 * In the rail fence cipher, the plaintext is written downwards and diagonally
 * on successive "rails" of an imaginary fence, then moving up when we reach the
 * bottom rail. When we reach the top rail, the message is written downwards
 * again until the whole plaintext is written out. The message is then read off
 * in rows.
 *
 * @see        http://en.wikipedia.org/wiki/Rail_Fence_Cipher
 * @see        http://www.cryptogram.org/cdb/aca.info/aca.and.you/chapter_09.pdf#RAILFE
 * @category   spica
 * @package    core
 * @subpackage crypto
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      March 31, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Crypto.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class SpicaCryptRailFenceCipher
{
    /**
     * Encodes a string using 2 fences.
     *
     * @param string $input String to encode
     */
    public static function encode($input)
    {
        $rail1 = "";
        $rail2 = "";
        $top   = true;

        for ($i = 0, $length = strlen($input); $i < $length; $i++)
        {
            if ($top == true)
            {
                $rail1 .= $input[$i];
            }
            else
            {
                $rail2 .= $input[$i];
            }

            $top = !$top;
        }

        return $rail1.$rail2;
    }

    /**
     * Decodes a string using 2 fences.
     *
     * @param string $input String to decode
     */
    public static function decode($input)
    {
        $decodedLength = strlen($input);

        $rail1    = substr($input, 0, $decodedLength/2);
        $rail2    = substr($input, $decodedLength/2);
        $r1       = 0;
        $r2       = 0;
        $original = '';
        $top      = true;

        while (strlen($original) != $decodedLength)
        {
            if ($top == true)
            {
                $original .= substr($rail1, $r1, 1);
                $r1++;
            }
            else
            {
                $original .= substr($rail2, $r2, 1);
                $r2++;
            }

            $top = !$top;
        }

        return $original;
    }
}

/**
 * This class provides some methods to work with AES encryption.
 *
 * @see        http://www.ciphersbyritter.com/GLOSSARY.HTM
 * @category   spica
 * @package    core
 * @subpackage crypto
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      April 01, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Crypto.php 1869 2011-01-07 18:55:25Z pcdinh $
 */

/**
 * @example
 *
 *   $cipher        = new SpicaCryptAESCipher('secret passphrase');
 *   $encryptedText = $cipher->encryptToHex(pack("H*", "1650f617c024d6441461b2538c6d9540"));
 *   $decryptedText = bin2hex($cipher->decryptHex($encryptedText));
 */
class SpicaCryptAESCipher
{
    /**
     * Secret passphrase to encrypt or decrypt a string.
     *
     * @var string
     */
    protected $_secretKey;

    /**
     * Initialization Vector (IV).
     *
     * @var string
     */
    protected $_iv;

    /**
     * Cipher name.
     *
     * @var int
     */
    protected $_cipherName;

    /**
     * Block cipher operating mode.
     *
     * @var int
     */
    protected $_mode;

    /**
     * Constructs a string using a secret passphrase.
     *
     * @param string $passPhrase String to use to produce secret passphrase
     * @param string $cipherName Cipher name
     * @param string $mode       Block cipher operating mode
     */
    public function __construct($passPhrase, $cipherName = MCRYPT_RIJNDAEL_128, $mode = MCRYPT_MODE_ECB)
    {
        $this->_cipherName = $cipherName;
        $this->_mode       = $mode;
        // mhash() produces a BIN output
        $this->_secretKey  = mhash(MHASH_SHA256, $passPhrase);
        $ivSize    = mcrypt_get_iv_size($this->_cipherName, $this->_mode);
        $this->_iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_RANDOM);
    }

    /**
     * Encodes a string.
     *
     * @param string $input String to encode
     */
    public function encrypt($input)
    {
        return mcrypt_encrypt($this->_cipherName, $this->_secretKey, $input, $this->_mode, $this->_iv);
    }

    /**
     * Decodes a string
     *
     * @param string $input String to decode
     */
    public function decrypt($input)
    {
        return trim(mcrypt_decrypt($this->_cipherName, $this->_secretKey, $input, $this->_mode, $this->_iv));
    }

    /**
     * Encodes a string, producing HEX output.
     *
     * @param string $input String to decode
     */
    public function encryptToHex($input)
    {
        return bin2hex($this->encrypt($input));
    }

    /**
     * Decodes a string in HEX output.
     *
     * @param string $input String to decode
     */
    public function decryptHex($input)
    {
        return $this->decrypt(pack("H*", $input));
    }
}

/**
 * This class provides HTTP Digest Authentication encryption.
 * FIXME
 *
 * @category   spica
 * @package    core
 * @subpackage crypto
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      April 07, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Crypto.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class SpicaHttpDigest
{
    /**
     * Creates base64 string from a given string.
     *
     * @param string $string
     */
    public static function base64Encode($string)
    {
        $s = '';

        for ($i  = 0, $length = strlen($string); i < $length;)
        {
            $pad = 0;
            $v   = ($string[$i++] & 0xff) << 16;

            if ($i < $length)
            {
                $v |= ($string[$i++] & 0xff) << 8;
            }
            else
            {
                $pad++;
            }

            if ($i < $length)
            {
                $v |= ($string[$i++] & 0xff);
            }
            else
            {
                $pad++;
            }

            $s .= self::encode($v >> 18);
            $s .= self::encode($v >> 12);

            if ($pad < 2)
            {
                $s .= self::encode($v >> 6);
            }
            else
            {
                $s .= '=';
            }

            if ($pad < 1)
            {
                $s .= self::encode($v);
            }
            else
            {
                $s .= '=';
            }
        }

        return $s;
    }

    /**
     * Encodes a character.
     *
     * @param string $i
     */
    public static function encode($i)
    {
        $i &= 0x3f;

        if ($i < 26)
        {
            return chr(ord('A'.$i));
        }

        if ($i < 52)
        {
            return chr(ord('a'.$i - 26));
        }

        if ($i < 62)
        {
            return chr(ord('0'.$i - 52));
        }

        return $i == 62 ? '+' : '/';
    }

    /**
     * Generates hash string from a password.
     *
     * @param string $password
     */
    public static function generateDigest($password)
    {
        $parts  = explode(":", $password, 2);
        $digest = sha1($password);
        return $parts[0] + ":" + self::base64Encode($digest);
    }
}

/**
 * This class provides SSL encryption and decryption service.
 *
 * @category   spica
 * @package    core
 * @subpackage crypto
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      April 07, 2009
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Crypto.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class SpicaSsl
{
    /**
     * Encrypts a string using SSL public key.
     *
     * @param  string $source
     * @param  string $pathToPubKey Path to certificate file "/path/to/certificate.crt"
     * @return string
     */
    public static function encrypt($source, $pathToPubKey = "public.key")
    {
        $fp     = fopen($pathToPubKey, "r");
        $pubKey = fread($fp, 8192);
        fclose($fp);
        openssl_get_publickey($pubKey);
        openssl_public_encrypt($source, $cryptText, $pubKey);
        return(base64_encode($cryptText));
    }

    /**
     * Decrypts a string using SSL public key.
     *
     * openssl genrsa -out private.key 2048
     * openssl rsa -pubout < private.key > public.key
     *
     * @param  string $source
     * @param  string $pathToPrivateKey
     * @param  string $passphrase Optional
     * @return string
     */
    public static function decrypt($source, $pathToPrivateKey = "private.key", $passphrase = null)
    {
        $fp     = fopen($pathToPrivateKey, "r");
        $privateKey = fread($fp, 8192);
        fclose($fp);
        $res    = openssl_get_privatekey($privateKey, $passphrase);
        $decodedSource = base64_decode($source);
        openssl_private_decrypt($decodedSource, $newsource, $res);
        return $newsource;
    }
}

?>